_Pragma("once");

#include <list>
//#include <pthread.h>
#include <mutex>
#include <condition_variable>
#include <chrono>
#include <ratio>
#include <cassert>


template <class T, class CONTAINER = std::list<T> >
class BoundedBuffer : public CONTAINER {
public:
    typedef CONTAINER container_type;
    typedef typename container_type::size_type size_type;
    typedef typename container_type::value_type value_type;

    typedef std::recursive_mutex MutexType;

    BoundedBuffer(size_t capacity);
    ~BoundedBuffer(void);


    bool lockForRead(void) {
        mmutex.lock();
        return true;
    }


    bool unlockForRead(void) {
        mmutex.unlock();
        return true;
    }


    size_t getCapacity(void) {
        return mcapacity;
    }


    bool pushPool(value_type& item, clock_t delay = 0, unsigned short loopCount = 0xffff) {
        bool result(false);
        std::cv_status waitCode(std::cv_status::timeout); //ETIMEDOUT
        unsigned short delta = 0xffff == loopCount ? 0 : 1;
        //  timespec absTime;

        std::unique_lock<MutexType> lock(mmutex);
        for (unsigned short i = 0; i < loopCount; i += delta) {
            if (isFull()) {
                if(0 == delay) {
                    continue;
                } else {
                    //     getTimeSpec(delay, absTime);

                    mnotifyNotFull = true;
                    // pthread_cond_timedwait(&mnotFull, &mmutex, &absTime);
                    waitCode = mnotFull.wait_for(lock, std::chrono::microseconds(delay));
                    continue;
                }
            } else {
                this->push_back(std::move(item));
                if (mnotifyNotEmpty) {
                    mnotifyNotEmpty = false;
                    //  pthread_cond_signal(&mnotEmpty);
                    mnotEmpty.notify_one();
                }
                result = true;
                break;
            }
        }

        return result;
    }


    bool popPool(value_type* pItem, clock_t delay = 0, unsigned short loopCount = 0xffff) {
        assert(NULL != pItem);

        bool result(false);
        std::cv_status waitCode(std::cv_status::timeout); //ETIMEDOUT
        unsigned short delta = 0xffff == loopCount ? 0 : 1;
        //   timespec absTime;

        std::unique_lock<MutexType> lock(mmutex);
        for (unsigned short i = 0; i < loopCount; i += delta) {
            if (this->empty()) {
                if(0 == delay) {
                    continue;
                } else {
                    //getTimeSpec(delay, absTime);

                    mnotifyNotEmpty = true;
                    //   waitCode = pthread_cond_timedwait(&mnotEmpty, &mmutex, &absTime);
                    waitCode = mnotEmpty.wait_for(lock, std::chrono::microseconds(delay));
                    continue;
                }
            } else {
                *pItem = std::move(this->back());
                this->pop_back();

                if (mnotifyNotFull) {
                    mnotifyNotFull = false;
                    //  pthread_cond_signal(&mnotFull);
                    mnotFull.notify_one();
                }
                result = true;
                break;
            }
        }
        return result;

    }


private:
    BoundedBuffer(const BoundedBuffer&);              // Disabled copy constructor
    BoundedBuffer& operator = (const BoundedBuffer&); // Disabled assign operator

    bool isFull() const {
        return this->size() >= mcapacity;
    }

    void getTimeSpec(clock_t delay, timespec& absTime) {
        clock_t absClock = clock() + delay;
        absTime.tv_sec = absClock / CLOCKS_PER_SEC;
        absTime.tv_nsec = ( absClock % CLOCKS_PER_SEC ) * 1000 * 1000;

    }

    const size_t            mcapacity;

//    pthread_rwlock_t        mrwlock;

    std::condition_variable_any          mnotEmpty;
    volatile bool           mnotifyNotEmpty;

    std::condition_variable_any    mnotFull;
    volatile bool           mnotifyNotFull;

    MutexType         mmutex;
};


template <class T, class CONTAINER>
BoundedBuffer<T, CONTAINER>::BoundedBuffer(size_t capacity) : mcapacity(capacity), mnotifyNotEmpty(false), mnotifyNotFull(false) {

}


template <class T, class CONTAINER>
BoundedBuffer<T, CONTAINER>::~BoundedBuffer() {
}




